use Purple;
use XML::XPath;
use XML::XPath::XMLParser;
use POSIX;

use strict;
use warnings;

our %PLUGIN_INFO = (
    perl_api_version => 2,
    name => "Twitter Status",
    version => "0.4.0",
    summary => "Use a Twitter feed as your status message.",
    description => "Use a Twitter feed as your status message.",
    author => 'Aaron D. Santos <aaronds109@gmail.com>, Kurt Nelson <kurt@thisisnotajoke.com>, '
	      .'Patrick Tulskie <patricktulskie@gmail.com> and Ramkumar R. Aiyengar <andyetitmoves@gmail.com>',
    url => "http://code.google.com/p/pidgin-twitterstatus/",

    load => "plugin_load",
    unload => "plugin_unload",
    prefs_info => "prefs_info_cb"
);

#Begin Global Variables
my $pref_root = "/plugins/core/gtk-aaron_ds-twitterstatus";
my $log_category = "Twitter Status Feed";
my $user_agent = "pidgin-twitterstatus/$PLUGIN_INFO{version}";
my $default_poll_interval = 120;
my $saved_status_name = 'Twitter';
#End Global Variables

sub parse_twitter_response
{
	my $twitter_response = shift;
	my $out_status;

	my $pref_ignore_replies = Purple::Prefs::get_bool("$pref_root/ignore_replies");
	my $pref_filter_regex = Purple::Prefs::get_string("$pref_root/filter_regex");

	Purple::Debug::info($log_category, "Preferences: "
			    ."ignore_replies = $pref_ignore_replies, "
			    ."filter_regex = '$pref_filter_regex'\n");

	my $last_seen_id = Purple::Prefs::get_int("$pref_root/state/last_seen_id");
	my $last_seen_id_dirty;

	my $twitter_xml = XML::XPath->new(xml=>$twitter_response);
	my @twitter_statuses = $twitter_xml->find('/statuses/status')->get_nodelist();
	foreach my $this_status (@twitter_statuses) {

		my $this_status_id = $this_status->find('id')->string_value;
		if ($this_status_id > $last_seen_id) {
			$last_seen_id = $this_status_id;
			$last_seen_id_dirty = 1;
		}
		my $this_status_message = $this_status->find('text')->string_value;
		Purple::Debug::info($log_category, "Found twitter status $this_status_id: '$this_status_message'\n");

		my $emsg = do {
			if ($this_status_id <= 0) { 'invalid status ID' }
			elsif (length($this_status_message) <= 1) { 'too short' }
			elsif ($pref_ignore_replies &&
			       ($this_status->find('in_reply_to_user_id')->string_value ||
				$this_status->find('in_reply_to_status_id')->string_value ||
				$this_status->find('in_reply_to_screen_name')->string_value)) { 'was a reply to someone' }
			elsif ($pref_filter_regex && $this_status_message =~ m/$pref_filter_regex/) { 'matched the discard filter' }
		};
		if ($emsg) {
			Purple::Debug::info($log_category, "Skipping status message: $emsg\n");
		} else {
			$out_status = $this_status;
			last;
		}
	}
	Purple::Prefs::set_int("$pref_root/state/last_seen_id", $last_seen_id) if $last_seen_id_dirty;
	return $out_status;
}

sub set_purple_status
{
	my $twitter_status = shift;

	my $status_message = Purple::Prefs::get_string("$pref_root/status_template");
	$status_message =~ s/\%\%/\%/g;
	$status_message =~ s/\%s/$twitter_status/g;

	my $purple_status = (Purple::SavedStatus::find($saved_status_name) || Purple::SavedStatus::new($saved_status_name, 2));
	$purple_status->set_message($status_message);

	my $cur_status = Purple::SavedStatus::get_default();
	my $cur_status_title = $cur_status->get_title();
	if ($cur_status_title && $cur_status_title eq $saved_status_name) {
		$purple_status->activate();
	}
}

sub fetch_url_cb
{
	my $twitter_response = shift;
	return unless $twitter_response;

	my $last_updated_id = Purple::Prefs::get_int("$pref_root/state/last_updated_id");

	my $twitter_status = parse_twitter_response($twitter_response);
	if ($twitter_status) {
		my $twitter_status_id = $twitter_status->find('id')->string_value;
		my $twitter_status_message = $twitter_status->find('text')->string_value;
		if ($twitter_status_id > $last_updated_id) {
			Purple::Debug::info($log_category, "Status is newer than the last twitter status we synced (ID: $last_updated_id)\n");
			set_purple_status $twitter_status_message;
			Purple::Prefs::set_int("$pref_root/state/last_updated_id", $twitter_status_id);
		}
	}
}

sub timeout_cb
{
	Purple::Debug::info($log_category, "Starting the sequence.  Pidgin's timer expired.\n");
	my $plugin = shift;
	my $poll_interval = (Purple::Prefs::get_int("$pref_root/poll_interval") || $default_poll_interval);

	if (Purple::Prefs::get_bool("$pref_root/discard_cache")) {
		Purple::Debug::info($log_category, "Discarding last seen ID cache as requested\n");
		Purple::Prefs::set_int("$pref_root/state/last_seen_id", 0);
		Purple::Prefs::set_bool("$pref_root/discard_cache", 0);
	}

	my $twitterusername = Purple::Prefs::get_string("$pref_root/twitterusername");
	if ($twitterusername =~ /[A-Za-z0-9_]+/) {
		my $api_root = Purple::Prefs::get_string("$pref_root/api_root");
		my (@url_params, $pref);
		$pref = Purple::Prefs::get_int("$pref_root/max_statuses_to_fetch");
		push @url_params, "count=$pref" if $pref > 0;
		$pref = Purple::Prefs::get_int("$pref_root/state/last_seen_id");
		push @url_params, "since_id=$pref" if $pref > 0;

		my $twitterurl = "$api_root/statuses/user_timeline/$twitterusername.xml?".(join '&', @url_params);

		Purple::Util::fetch_url($plugin, $twitterurl, 1, $user_agent, 1, "fetch_url_cb");
	} else {
		Purple::Debug::error($log_category, "Blank or invalid username: '$twitterusername'\n");
	}

	# Reschedule timeout
	Purple::Debug::info($log_category, "Rescheduling timer.\n");
	Purple::timeout_add($plugin, $poll_interval, \&timeout_cb, $plugin);
	Purple::Debug::info($log_category, "New timer set for " . $poll_interval . " seconds.\n");
}

sub send_tweet
{
	my $status = shift;
	Purple::Debug::warning($log_category, "Send tweet: STUB: '$status'\n");
	return 0; # Should return update_id, 0 means not successful.
}

sub plugin_init
{
    return %PLUGIN_INFO;
}

sub plugin_load
{
    my $plugin = shift;
    Purple::Debug::info($log_category, "plugin_load() - Twitter Status Feed.\n");

    # Here we are adding a set of preferences
    #  The second argument is the default value for the preference.
    Purple::Prefs::add_none("$pref_root");
    Purple::Prefs::add_string("$pref_root/twitterusername", "");
    Purple::Prefs::add_string("$pref_root/twitterpassword", "");
    Purple::Prefs::add_string("$pref_root/filter_regex", "");
    Purple::Prefs::add_bool("$pref_root/sendstatus", "");
    Purple::Prefs::add_int("$pref_root/poll_interval", $default_poll_interval);
    Purple::Prefs::add_bool("$pref_root/ignore_replies", 1);
    Purple::Prefs::add_int("$pref_root/max_statuses_to_fetch", 0);
    Purple::Prefs::add_string("$pref_root/api_root", "http://twitter.com");
    Purple::Prefs::add_bool("$pref_root/discard_cache", 0);
    Purple::Prefs::add_string("$pref_root/status_template", '%s');

    Purple::Prefs::add_none("$pref_root/state");
    Purple::Prefs::add_int("$pref_root/state/last_seen_id", 0);
    Purple::Prefs::add_int("$pref_root/state/last_updated_id", 0);

    # Create the saved status early, so that user can set it before the first twitter update
    Purple::SavedStatus::find($saved_status_name) || Purple::SavedStatus::new($saved_status_name, 2);

    # Schedule a timeout for 10 seconds from now
    Purple::timeout_add($plugin, 10, \&timeout_cb, $plugin);
}

sub plugin_unload
{
    my $plugin = shift;
    Purple::Debug::info($log_category, "plugin_unload() - Twitter Status Feed.\n");
}

sub prefs_info_cb
{
    my ($frame, $ppref);

    # The first step is to initialize the Purple::Pref::Frame that will be returned
    $frame = Purple::PluginPref::Frame->new();

    $frame->add(Purple::PluginPref->new_with_label("Twitter Account Information"));
    $frame->add(Purple::PluginPref->new_with_name_and_label("$pref_root/twitterusername", "Twitter User Name"));
# Let's expose this, and sendstatus, when send_tweet is anything better than a stub.
#   $frame->add(Purple::PluginPref->new_with_name_and_label("$pref_root/twitterpassword", "Twitter Password (Optional)"));

    $frame->add(Purple::PluginPref->new_with_label("Options"));
    $ppref = Purple::PluginPref->new_with_name_and_label("$pref_root/poll_interval", "Poll Interval (in seconds)");
    $ppref->set_bounds(40, 900); # Twitter has 100 per hour IP limit, which means 36 seconds between polls
    $frame->add($ppref);
    $frame->add(Purple::PluginPref->new_with_name_and_label("$pref_root/ignore_replies", "Ignore reply tweets"));
    $frame->add(Purple::PluginPref->new_with_name_and_label("$pref_root/status_template", "Status message template"));
#   $frame->add(Purple::PluginPref->new_with_name_and_label("$pref_root/sendstatus", "Tweet my status message when I change it in Pidgin"));

    $frame->add(Purple::PluginPref->new_with_label("Advanced Options"));
    $frame->add(Purple::PluginPref->new_with_name_and_label("$pref_root/filter_regex", "Ignore regexp for tweets"));
    $frame->add(Purple::PluginPref->new_with_name_and_label("$pref_root/api_root", "API Root URL"));
    $ppref = Purple::PluginPref->new_with_name_and_label("$pref_root/max_statuses_to_fetch", "Maximum statuses to request");
    $ppref->set_bounds(0, 100); # Twitter anyway doesn't return more than 20
    $frame->add($ppref);

    $frame->add(Purple::PluginPref->new_with_label("Debugging"));
    $frame->add(Purple::PluginPref->new_with_name_and_label("$pref_root/discard_cache", "Discard any cached information on next run"));

    return $frame;
}
